﻿//using Core.Experiment;
//using System.Collections.Generic;
//using UnityEngine;

////for more on A* visit
////https://en.wikipedia.org/wiki/A*_search_algorithm

//namespace Core.Experiment
//{
//    public class AstarPathfinder
//    {
//        public PathComponent gridBase;
//        public Node startPosition;
//        public Node endPosition;

//        public volatile bool jobDone = false;

//        public void FindPath(ref List<Node> foundPath, Node start, Node target)
//        {
//            foundPath.Clear();

//            startPosition = start;
//            endPosition = target;

//            FindPathActual(ref foundPath, startPosition, endPosition);

//            jobDone = true;
//        }

//        private List<Node> openList = new List<Node>();
//        private HashSet<Node> closedSet = new HashSet<Node>();
//        private void FindPathActual(ref List<Node> foundPath, Node start, Node target)
//        {
//            openList.Clear();
//            closedSet.Clear();

//            //We start adding to the open set
//            openList.Add(start);

//            while (openList.Count > 0)
//            {
//                Node currentNode = openList[0];

//                for (int i = 0; i < openList.Count; i++)
//                {
//                    var n = openList[i];
//                    //We check the costs for the current node
//                    //You can have more opt. here but that's not important now
//                    if (n.fCost < currentNode.fCost ||
//                        (n.fCost == currentNode.fCost &&
//                        n.hCost < currentNode.hCost))
//                    {
//                        //and then we assign a new current node
//                        if (!currentNode.Equals(n))
//                        {
//                            currentNode = n;
//                        }
//                    }
//                }

//                //we remove the current node from the open set and add to the closed set
//                openList.Remove(currentNode);
//                closedSet.Add(currentNode);

//                //if the current node is the target node
//                if (currentNode.Equals(target))
//                {
//                    //that means we reached our destination, so we are ready to retrace our path
//                    RetracePath(ref foundPath, start, currentNode);
//                    break;
//                }

//                //if we haven't reached our target, then we need to start looking the neighbours
//                foreach (Node neighbour in GetNeighbours(currentNode))
//                {
//                    if (!closedSet.Contains(neighbour))
//                    {
//                        //we create a new movement cost for our neighbours
//                        float newMovementCostToNeighbour = currentNode.gCost + GetDistance(currentNode, neighbour);

//                        //and if it's lower than the neighbour's cost
//                        if (newMovementCostToNeighbour < neighbour.gCost || !openList.Contains(neighbour))
//                        {
//                            //we calculate the new costs
//                            neighbour.gCost = newMovementCostToNeighbour;
//                            neighbour.hCost = GetDistance(neighbour, target);
//                            //Assign the parent node
//                            neighbour.parentNode = currentNode;
//                            //And add the neighbour node to the open set
//                            if (!openList.Contains(neighbour))
//                            {
//                                openList.Add(neighbour);
//                            }
//                        }
//                    }
//                }
//            }
//        }

//        private void RetracePath(ref List<Node> foundPath, Node startNode, Node endNode)
//        {
//            //Retrace the path, is basically going from the endNode to the startNode
//            Node currentNode = endNode;

//            while (currentNode != startNode)
//            {
//                foundPath.Add(currentNode);
//                //by taking the parentNodes we assigned
//                currentNode = currentNode.parentNode;
//            }

//            //then we simply reverse the list
//            foundPath.Reverse();

//        }

//        private List<Node> GetNeighbours(Node node)
//        {
//            //This is were we start taking our neighbours
//            List<Node> retList = new List<Node>();

//            for (int x = -1; x <= 1; x++)
//            {
//                for (int z = -1; z <= 1; z++)
//                {

//                    if (x == 0 && z == 0)
//                    {
//                        //000 is the current node
//                        continue;
//                    }

//                    Node newNode = GetNeighbourNode(node.x + x, node.z + z, node);

//                    if (newNode != null)
//                    {
//                        retList.Add(newNode);
//                    }
//                }
//            }

//            return retList;

//        }

//        private Node GetNeighbourNode(int adj_x, int adj_z, Node currentNodePos)
//        {
//            //this is where the meat of it is
//            //We can add all the checks we need here to tweak the algorythm to our heart's content
//            //but first let's start from the the usual stuff you'll see in A*

//            Node retVal = null;

//            //let's take the node from the adjacent positions we passed
//            Node node = GetNode(adj_x, adj_z);

//            //if it's not null and we can walk on it
//            if (node != null && node.isWalkable)
//            {
//                //we can use that node
//                retVal = node;
//            }

//            //if the node is diagonal to the current node then check the neighbouring nodes
//            //so to move diagonally, we need to have 4 nodes walkable
//            int originalX = adj_x - currentNodePos.x;
//            int originalZ = adj_z - currentNodePos.z;

//            if (Mathf.Abs(originalX) == 1 && Mathf.Abs(originalZ) == 1)
//            {
//                // the first block is originalX, 0 and the second to check is 0, originalZ
//                //They need to be pathfinding walkable
//                Node neighbour1 = GetNode(currentNodePos.x + originalX, currentNodePos.z);
//                if (neighbour1 == null || !neighbour1.isWalkable)
//                {
//                    retVal = null;
//                }

//                Node neighbour2 = GetNode(currentNodePos.x, currentNodePos.z + originalZ);
//                if (neighbour2 == null || !neighbour2.isWalkable)
//                {
//                    retVal = null;
//                }
//            }

//            return retVal;
//        }

//        private Node GetNode(int x, int z)
//        {
//            Node n = null;

//            lock (gridBase)
//            {
//                n = gridBase.GetNode(x, z);
//            }
//            return n;
//        }

//        private int GetDistance(Node posA, Node posB)
//        {
//            //We find the distance between each node
//            //not much to explain here

//            int distX = Mathf.Abs(posA.x - posB.x);
//            int distZ = Mathf.Abs(posA.z - posB.z);

//            if (distX > distZ)
//            {
//                return 14 * distZ + 10 * (distX - distZ);
//            }

//            return 14 * distX + 10 * (distZ - distX);
//        }

//    }
//}